package com.smalldragon.yml.testutils;

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisClusterConnection;
import org.springframework.data.redis.connection.RedisSentinelConnection;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;

import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 简化的Mock测试工具类
 * 提供基本的Mock实现用于测试
 */
public class MockTestUtils {

    /**
     * Mock Redis Connection Factory for testing
     * 这是一个简化的Mock实现，仅用于编译通过
     */
    public static class MockRedisConnectionFactory implements RedisConnectionFactory {

        @Override
        public RedisConnection getConnection() {
            // 抛出异常，提示测试应该使用真实的Redis配置
            throw new UnsupportedOperationException(
                "MockRedisConnectionFactory should not be used in tests. " +
                "Please configure a real Redis connection or use @MockBean annotation.");
        }

        @Override
        public RedisClusterConnection getClusterConnection() {
            return null;
        }

        @Override
        public boolean getConvertPipelineAndTxResults() {
            return false;
        }

        @Override
        public RedisSentinelConnection getSentinelConnection() {
            return null;
        }

        @Override
        public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
            return null;
        }
    }

    /**
     * Mock Session Repository for testing
     */
    public static class MockSessionRepository implements SessionRepository<MockSession> {
        private final Map<String, MockSession> sessions = new ConcurrentHashMap<>();

        @Override
        public MockSession createSession() {
            return new MockSession();
        }

        @Override
        public void save(MockSession session) {
            sessions.put(session.getId(), session);
        }

        @Override
        public MockSession findById(String id) {
            return sessions.get(id);
        }

        @Override
        public void deleteById(String id) {
            sessions.remove(id);
        }
    }

    /**
     * Mock Session implementation
     */
    public static class MockSession implements Session {
        private final String id = UUID.randomUUID().toString();
        private final Map<String, Object> attributes = new ConcurrentHashMap<>();
        private Instant creationTime = Instant.now();
        private Instant lastAccessedTime = Instant.now();
        private Duration maxInactiveInterval = Duration.ofMinutes(30);
        private boolean expired = false;

        @Override
        public String getId() {
            return id;
        }

        @Override
        public String changeSessionId() {
            return getId();
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T getAttribute(String attributeName) {
            return (T) attributes.get(attributeName);
        }

        @Override
        public Set<String> getAttributeNames() {
            return attributes.keySet();
        }

        @Override
        public void setAttribute(String attributeName, Object attributeValue) {
            attributes.put(attributeName, attributeValue);
        }

        @Override
        public void removeAttribute(String attributeName) {
            attributes.remove(attributeName);
        }

        @Override
        public Instant getCreationTime() {
            return creationTime;
        }

        @Override
        public void setLastAccessedTime(Instant lastAccessedTime) {
            this.lastAccessedTime = lastAccessedTime;
        }

        @Override
        public Instant getLastAccessedTime() {
            return lastAccessedTime;
        }

        @Override
        public void setMaxInactiveInterval(Duration interval) {
            this.maxInactiveInterval = interval;
        }

        @Override
        public Duration getMaxInactiveInterval() {
            return maxInactiveInterval;
        }

        @Override
        public boolean isExpired() {
            return expired || Instant.now().isAfter(lastAccessedTime.plus(maxInactiveInterval));
        }
    }
}